﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Core.Extensions
{
	using System;
	using System.Globalization;

	public static class EnumExtensions
	{
		/// <summary>
		/// Determines whether the Enum has the specified values.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="source">The source.</param>
		/// <param name="values">The values.</param>
		/// <returns>
		/// 	<c>true</c> if Enum has the specified values; otherwise, <c>false</c>.
		/// </returns>
		public static bool Has<T>(this Enum source, params T[] values)
		{
			var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);

			foreach (var i in values)
			{
				var mask = Convert.ToInt32(i, CultureInfo.InvariantCulture);

				if ((value & mask) == 0)
				{
					return false;
				}
			}

			return true;
		}

		/// <summary>
		/// Determines whether the Enum has the specified value.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="source">The source.</param>
		/// <param name="values">The values.</param>
		/// <returns>
		/// 	<c>true</c> if Enum has the specified value; otherwise, <c>false</c>.
		/// </returns>
		public static bool Has<T>(this Enum source, T values)
		{
			var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
			var mask = Convert.ToInt32(values, CultureInfo.InvariantCulture);

			return (value & mask) != 0;
		}

		/// <summary>
		/// Adds the specified value to the enum.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="source">The source.</param>
		/// <param name="v">The value.</param>
		/// <returns></returns>
		public static T Add<T>(this Enum source, T v)
		{
			var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
			var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);

			return Enum.ToObject(typeof(T), value | mask).As<T>();
		}

		/// <summary>
		/// Removes the specified value from the enum.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="source">The source.</param>
		/// <param name="v">The value.</param>
		/// <returns></returns>
		public static T Remove<T>(this Enum source, T v)
		{
			var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
			var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);

			return Enum.ToObject(typeof(T), value & ~mask).As<T>();
		}

		/// <summary>
		/// Gets the max value of the specified enum.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="source">The source.</param>
		/// <returns></returns>
		public static T Max<T>(this Enum source)
		{
			var mask = 0;
			var values = Enum.GetValues(typeof(T));

			foreach (var value in values)
			{
				mask |= Convert.ToInt32(value, CultureInfo.InvariantCulture);
			}

			return Enum.ToObject(typeof(T), mask).As<T>();
		}

		/// <summary>
		/// Gets the name of the specified enum source.
		/// </summary>
		/// <param name="source">The source.</param>
		/// <returns></returns>
		public static string Name(this Enum source)
		{
			return Enum.GetName(source.GetType(), source);
		}

		/// <summary>
		/// Converts the string value to the enum.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="value">The value.</param>
		/// <returns></returns>
		public static T AsEnum<T>(this string value)
		{
			try
			{
				return Enum.Parse(typeof(T), value, true).As<T>();
			}
			catch
			{
				return default(T);
			}
		}
	}
}